package ch.ethz.fcl.metrobuzz.render.techniques.circos.version3;

import javax.vecmath.Vector2d;

import ch.ethz.fcl.metrobuzz.render.techniques.circos.CircosMatrix;
import ch.ethz.fcl.metrobuzz.render.techniques.circos.version2.CircosDiagram2;
import ch.ethz.fcl.metrobuzz.spatialindex.object2d.Point2D;
import ch.ethz.fcl.metrobuzz.tools.MBTools;
import ch.ethz.fcl.metrofont.MetroFont;

/**
 * 
 * @author Zeng Wei
 * @email zeng@arch.ethz.ch
 * 
 *        Compare with version 2, bundle bidirectional ribbons together
 */
public class CircosDiagram3 extends CircosDiagram2 {
	public CircosDiagram3(Point2D center, float radius, CircosMatrix matrix) {
		super(center, radius, matrix);
	}

	public void render(MetroFont fm) {
		super.render(fm);
		renderInOutRatio();
	}

	public void update() {
		gap = (float) Math.min(gap, Math.PI / (data.size() - 1) / 2);

		float[][] distri = data.getData();
		float[] outgoing = data.getOutgoing();
		float[] incoming = data.getIncoming();

		if (data.getTotalSum() <= 0)
			return;

		Vector2d[] dirs = data.getDirections().getNonOverlapDirections(gap,
				renderAngle, minRenderAngle);
		int[][] outRenderOrder = data.getSubRenderOrder();
		int[] renderOrder = data.getRenderOrder();

		outgoingStartPoints = new Point2D[data.size()][data.size()];
		outgoingEndPoints = new Point2D[data.size()][data.size()];
		incomingStartPoints = new Point2D[data.size()][data.size()];
		incomingEndPoints = new Point2D[data.size()][data.size()];

		for (int i = 0; i < renderOrder.length; i++) {
			int renderIndex = renderOrder[i];

			float arcAngle = renderAngle
					* (incoming[renderIndex] + outgoing[renderIndex])
					/ (data.getTotalSum() - (incoming[0] + outgoing[0]));

			MBTools.debug("index " + renderIndex + " sum "
					+ (outgoing[renderIndex] + incoming[renderIndex])
					+ " eclipse angle " + arcAngle, false);

			Vector2d startDir = MBTools
					.rotate(dirs[renderIndex], -arcAngle / 2);

			Vector2d dir = startDir;
			for (int j = 0; j < outRenderOrder[renderIndex].length; j++) {
				int sortedIndex = outRenderOrder[renderIndex][j];
				Point2D outgoingStart = center.getPointAt(dir, radius);
				float outgoingAngle = distri[renderIndex][sortedIndex]
						/ (outgoing[renderIndex] + incoming[renderIndex])
						* arcAngle;

				outgoingStartPoints[renderIndex][sortedIndex] = outgoingStart;

				dir = MBTools.rotate(dir, outgoingAngle);

				outgoingEndPoints[renderIndex][sortedIndex] = center
						.getPointAt(dir, radius);

				float incomingAngle = distri[sortedIndex][renderIndex]
						/ (outgoing[renderIndex] + incoming[renderIndex])
						* arcAngle;

				incomingStartPoints[sortedIndex][renderIndex] = center
						.getPointAt(dir, radius * arcElementRibbonGapRatio);
				dir = MBTools.rotate(dir, incomingAngle);
				incomingEndPoints[sortedIndex][renderIndex] = center
						.getPointAt(dir, radius * arcElementRibbonGapRatio);
			}
		}

		for (int i = 1; i < data.size(); i++) {
			float ratioIncoming = flyoverRingRadius * flyoverRingOutRatio
					* flyoverRingRibbonGapRatio / radius;
			float ratioOutgoing = flyoverRingRadius * flyoverRingOutRatio
					/ (radius * arcElementRibbonGapRatio);
			incomingStartPoints[i][0] = center.getPointAt(
					outgoingStartPoints[i][0], ratioIncoming);
			incomingEndPoints[i][0] = center.getPointAt(
					outgoingEndPoints[i][0], ratioIncoming);
			outgoingStartPoints[0][i] = center.getPointAt(
					incomingStartPoints[0][i], ratioOutgoing);
			outgoingEndPoints[0][i] = center.getPointAt(
					incomingEndPoints[0][i], ratioOutgoing);
		}
	}

	public void setGlobalMax(float max) {
		renderAngle = (float) (data.getTotalSum() / max * Math.PI);
		update();
	}
}
